package com.jse.util;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
 
 
/**
 * Encrypt
 * @author dzh
 * @date 2010-04-19
 */
public class Encrypt {
 
	/**
	 * des加密
	 * @param password 8位
	 * @param src
	 * @return
	 */
	public static byte[] desencrypt(String password,String src) {
		return encrypt("DES", password, src);
	}
	/**
	 * des解密
	 * @param password 8位
	 * @param src
	 * @return
	 */
	public static String desdecrypt(String password,byte[] src) {
		return decrypt("DES", password, src);
	}
    /**
     * 加密方法
     * @param Algorithm DES、DESede(即3DES)、Blowfish
     * @param password 密码
     * @param src 源数据
     * @return 
     */
    public static byte[] encrypt(String Algorithm,String password,String src) {
    	try {
    		byte[] keys=password.getBytes();
    		if(!Algorithm.equals("DES")) {
    			keys=deskey(password);
    		}
            SecretKey deskey = new SecretKeySpec(keys, Algorithm);    //生成密钥
            Cipher c1 = Cipher.getInstance(Algorithm);    //实例化负责加密/解密的Cipher工具类
            c1.init(Cipher.ENCRYPT_MODE, deskey);    //初始化为加密模式
            return c1.doFinal(src.getBytes());
        } catch (java.security.NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        } catch (javax.crypto.NoSuchPaddingException e2) {
            e2.printStackTrace();
        } catch (java.lang.Exception e3) {
            e3.printStackTrace();
        }
         return null;
     }
    
    
    /**
     * 解密函数
     * @param Algorithm DES、DESede(即3DES)、Blowfish
     * @param password 密码
     * @param src 密文字节数组
     * @return
     */
    public static String decrypt(String Algorithm,String password,byte[] src) {      
    	try {
    		byte[] keys=password.getBytes();
    		if(!Algorithm.equals("DES")) {
    			keys=deskey(password);
    		}
            SecretKey deskey = new SecretKeySpec(keys, Algorithm);
            Cipher c1 = Cipher.getInstance(Algorithm);
            c1.init(Cipher.DECRYPT_MODE, deskey);    //初始化为解密模式
            return new String(c1.doFinal(src));
        } catch (java.security.NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        } catch (javax.crypto.NoSuchPaddingException e2) {
            e2.printStackTrace();
        } catch (java.lang.Exception e3) {
            e3.printStackTrace();
        }
        return null;
     }
    
    
    /**
     * 根据字符串生成密钥字节数组 
     * @param password 密钥字符串
     * @return 
     * @throws UnsupportedEncodingException
     */
    public static byte[] deskey(String password) throws UnsupportedEncodingException{
    	byte[] key = new byte[24];    //声明一个24位的字节数组，默认里面都是0
        byte[] temp = password.getBytes("UTF-8");    //将字符串转成字节数组
        
        /*
         * 执行数组拷贝
         * System.arraycopy(源数组，从源数组哪里开始拷贝，目标数组，拷贝多少位)
         */
        if(key.length > temp.length){
            //如果temp不够24位，则拷贝temp数组整个长度的内容到key数组中
            System.arraycopy(temp, 0, key, 0, temp.length);
        }else{
            //如果temp大于24位，则拷贝temp数组24个长度的内容到key数组中
            System.arraycopy(temp, 0, key, 0, key.length);
        }
        return key;
    }
    
    private static final int BLOCK_SIZE = 32;

	/**
	 * 
	 * <p>
	 * 获得对明文进行补位填充的字节
	 * </p>
	 * 
	 * @param count
	 * 				需要进行填充补位操作的明文字节个数
	 * @return 补齐用的字节数组
	 */
	public static byte[] pkcs7Encode(int count,Charset charset) {

		/* 计算需要填充的位数 */
		int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
		if (amountToPad == 0) {
			amountToPad = BLOCK_SIZE;
		}
		
		/* 获得补位所用的字符 */
		char padChr = pkcs7chr(amountToPad);
		String tmp = new String();
		for (int index = 0; index < amountToPad; index++) {
			tmp += padChr;
		}
		return tmp.getBytes(charset);
	
	}
	public static byte[] pkcs7Encode(int count) {
		return pkcs7Encode(count,StandardCharsets.UTF_8);
		
	}

	/**
	 * 
	 * <p>
	 * 删除解密后明文的补位字符
	 * </p>
	 * 
	 * @param decrypted
	 * 					解密后的明文
	 * @return 删除补位字符后的明文
	 */
	public static byte[] pkcs7Decode(byte[] decrypted) {
		int pad = (int) decrypted[decrypted.length - 1];
		if (pad < 1 || pad > 32) {
			pad = 0;
		}
		return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
	}

	/**
	 * 
	 * <p>
	 * 将数字转化成ASCII码对应的字符，用于对明文进行补码
	 * </p>
	 * 
	 * @param a
	 * 			需要转化的数字
	 * @return 转化得到的字符
	 */
	public static char pkcs7chr(int a) {
		byte target = (byte) (a & 0xFF);
		return (char) target;
	}
    
	/**
	 * 加解密算法/工作模式/填充方式
	 */
	private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS5Padding";

	/**
	 * AES加密
	 * 
	 * @param data
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static String aesencrypt(String data, String key) {
		try {
			// 创建密码器
			Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
			// 初始化
			cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Lang.md5(key).toLowerCase().getBytes(), "AES"));
			return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
		} catch (Exception e) {
			throw new RuntimeException("Aes 加密出错",e);
		}
	}
	public static String pkcs5encrypt(String data, String key) {
		try {
			// 创建密码器
			Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
			// 初始化
			cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Lang.md5(key).toLowerCase().getBytes(), "AES"));
			return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
		} catch (Exception e) {
			throw new RuntimeException("Aes 加密出错",e);
		}
	}
	public static String ecbencrypt(String data, String key) {
		try {
			// 创建密码器
			Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
			// 初始化
			cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Lang.md5(key).toLowerCase().getBytes(), "ECB"));
			return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
		} catch (Exception e) {
			throw new RuntimeException("Aes 加密出错",e);
		}
	}

	/**
	 * AES解密
	 * 
	 * @param base64Data
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static String aesdecrypt(String base64Data, String key) {
		try {
		Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
		cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Lang.md5(key).toLowerCase().getBytes(), "AES"));
		return new String(cipher.doFinal(Base64.getDecoder().decode(base64Data)));
		} catch (Exception e) {
			throw new RuntimeException("Aes 解密出错",e);
		}
	}
	public static String ecbdecrypt(String base64Data, String key) {
		try {
		Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
		cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Lang.md5(key).toLowerCase().getBytes(), "ECB"));
		return new String(cipher.doFinal(Base64.getDecoder().decode(base64Data)));
		} catch (Exception e) {
			throw new RuntimeException("Aes 解密出错",e);
		}
	}
	public static String pkcs5decrypt(String base64Data, String key) {
		try {
		Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
		cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Lang.md5(key).toLowerCase().getBytes(), "ECB"));
		return new String(cipher.doFinal(Base64.getDecoder().decode(base64Data)));
		} catch (Exception e) {
			throw new RuntimeException("Aes 解密出错",e);
		}
	}
	
    public static void main(String[] args) {
//        String msg = "des加密解密案例";
//        System.out.println("【加密前】：" + msg);
//        //加密 DES、DESede(即3DES)、Blowfish
//        byte[] secretArr = desencrypt("DES","dd111111",msg);    
//        System.out.println("【加密后】：" + new String(secretArr));
//        //解密 DES、DESede(即3DES)、Blowfish
//        String myMsgArr = desdecrypt("DES","dd111111",secretArr);  
//        System.out.println("【解密后】：" + new String(myMsgArr));
    	byte[] cipherText = desencrypt("dd111111", "11aaa1");
		System.out.println("密文: " + cipherText);

		String clearText = desdecrypt("dd111111",cipherText);
		System.out.println("明文：" + clearText);
    }

}